﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DVK.SP2007;
using Microsoft.SharePoint;
using DVK.SP2007.Constants;
using System.Web.Script.Serialization;
using System.Text;

namespace DVK.SP2007
{
    /// <summary>
    /// MetadataMappingManager helps access information (items) from SharePoint Metadata mappings list. 
    /// </summary>
    public class MetadataMappingRepository
    {
        SPWeb _web;

        /// <summary>
        /// Initializes a new instance of the <see cref="MetadataMappingManager"/> class.
        /// </summary>
        /// <param name="web">The web.</param>
        public MetadataMappingRepository(SPWeb web)
        {
            _web = web;
        }

        /// <summary>
        /// Gets the metadata mapping list.
        /// <remarks>
        /// Currently always loads new instance of the MetadataMapping list.
        /// No caching is used.
        /// </remarks>
        /// </summary>
        /// <returns></returns>
        public SPList GetMetadataMappingList()
        {
            //TODO: Perhaps a cache can be used for this list and it could be dependant on configuration changes (Taavi, Date)
            return _web.GetListFromUrl(Urls.ListMetadataMapping);
        }

        /// <summary>
        /// Gets the mapping from metadata mapping listitem field "DvkMetadataMapping".
        /// <remarks>
        /// Looks up the listitem with matching mapping level, identifier and applying to value.
        /// Note: Identifier is not currently in use.
        /// 
        /// Takes the first item with applying to value. If one does not exist, it takes the one with applyingto as "All".
        /// 
        /// After the item has been found, DvkMetadataMapping field contains a JSON format string, which is parsed into "List<DvkMapping>".
        /// The resulting list is returned.
        /// </remarks>
        /// </summary>
        /// <param name="mappingLevel">The mapping level.</param>
        /// <param name="identifier">The identifier.</param>
        /// <param name="applyingTo">The applying to.</param>
        /// <returns>mappings list</returns>
        public List<DvkMapping> GetMapping(
            Fields.DvkMappingLevel.DvkMappingLevelChoices mappingLevel,
            string identifier,
            Fields.DvkMappingApplyingTo.DvkMappingApplyingToChoices applyingTo)
        {
            SPListItemCollection items = GetMetadataMappingItem(mappingLevel, identifier, applyingTo);

            if (items.Count == 0)
                return new List<DvkMapping>();

            SPListItem item = null;

            //Prefer the applying to value
            foreach (SPListItem mitem in items)
            {
                if ((mitem[Fields.DvkMappingApplyingTo.Name] as string) == applyingTo.ToString())
                {
                    item = mitem;
                    break;
                }
            }

            //If there is no In or Out item, then Get "All" item (applies to both in and out mapping)
            if (item == null)
            {
                foreach (SPListItem mitem in items)
                {
                    if ((mitem[Fields.DvkMappingApplyingTo.Name] as string) == Fields.DvkMappingApplyingTo.DvkMappingApplyingToChoices.All.ToString())
                    {
                        item = mitem;
                        break;
                    }
                }
            }

            var mappingString = item[Fields.DvkMetadataMapping.Name] as string;
            var result = new JavaScriptSerializer().Deserialize<List<DvkMapping>>(mappingString);
            return result;
        }

        /// <summary>
        /// Gets the metadata mapping item by mapping level, identifier and applyingto.
        /// <remarks>
        /// Looks up the listitem with matching mapping level, identifier and applying to value.
        /// Note: Identifier is not currently in use.
        /// 
        /// Takes the first item with applying to value. If one does not exist, it takes the one with applyingto as "All".
        /// 
        /// </remarks>
        /// </summary>
        /// <param name="mappingLevel">The mapping level.</param>
        /// <param name="identifier">The identifier.</param>
        /// <param name="applyingTo">The applying to.</param>
        /// <returns></returns>
        public SPListItemCollection GetMetadataMappingItem(
            Fields.DvkMappingLevel.DvkMappingLevelChoices mappingLevel, 
            string identifier,
            Fields.DvkMappingApplyingTo.DvkMappingApplyingToChoices applyingTo)
        {
            SPList metadataMappingList = GetMetadataMappingList();

            //TODO: Identifier support has to be implemented sometime later (Taavi, Date)
            SPQuery query = new SPQuery();

            string queryString = string.Format(
                                  @"<Where>
                                    <Or>
                                        <Eq><FieldRef Name='{0}' /><Value Type='Choice'>{1}</Value></Eq>
                                        <Eq><FieldRef Name='{2}' /><Value Type='Choice'>{3}</Value></Eq>
                                    </Or>
                                    <Eq><FieldRef Name='{4}' /><Value Type='Choice'>{5}</Value></Eq>
                                  </Where>",
                                    Fields.DvkMappingApplyingTo.Name,
                                    Fields.DvkMappingApplyingTo.DvkMappingApplyingToChoices.All.ToString(),
                                    Fields.DvkMappingApplyingTo.Name,
                                    applyingTo.ToString(),
                                    Fields.DvkMappingLevel.Name,
                                    mappingLevel.ToString()
                                  );

            query.Query = queryString;
            query.RowLimit = 10;

            SPListItemCollection items = metadataMappingList.GetItems(query);
            return items;
        }

        /// <summary>
        /// Gets the unique metadata mapping item by mapping level, identifier and applying to.
        /// <remarks>
        /// Note: Identifier is not currently in use.
        /// </remarks>
        /// </summary>
        /// <param name="mappingLevel">The mapping level.</param>
        /// <param name="identifier">The identifier.</param>
        /// <param name="applyingTo">The applying to.</param>
        /// <returns></returns>
        public SPListItemCollection GetUniqueMetadataMappingItem(
            Fields.DvkMappingLevel.DvkMappingLevelChoices mappingLevel, 
            string identifier,
            Fields.DvkMappingApplyingTo.DvkMappingApplyingToChoices applyingTo)
        {
            SPList metadataMappingList = GetMetadataMappingList();

            //TODO: Identifier support has to be implemented sometime later (Taavi, Date)
            SPQuery query = new SPQuery();

            string queryString = string.Format(
                                  @"<Where>
                                    <And>
                                        <Eq><FieldRef Name='{0}' /><Value Type='Choice'>{1}</Value></Eq>
                                        <Eq><FieldRef Name='{2}' /><Value Type='Choice'>{3}</Value></Eq>
                                    </And>
                                  </Where>",
                                    Fields.DvkMappingApplyingTo.Name,
                                    applyingTo.ToString(),
                                    Fields.DvkMappingLevel.Name,
                                    mappingLevel.ToString()
                                  );

            query.Query = queryString;
            query.RowLimit = 1;

            SPListItemCollection items = metadataMappingList.GetItems(query);
            return items;
        }

        /// <summary>
        /// Gets the metadata mapping item from metadata mapping list.
        /// </summary>
        /// <param name="itemId">The listitem id.</param>
        /// <returns>listitem from metadata mapping list</returns>
        public SPListItem GetMetadataMappingItem(int itemId)
        {
            SPList list = GetMetadataMappingList();
            return list.GetItemById(itemId);
        }
    }
}
